/**
 * 校验模块
 * @author holyhigh
 */

/**
 * 是否有效身份证号码(18位)
 * @param {string} idStr 验证字符串
 * @return {boolean}
 */
function isIdNumber(idStr: string): boolean {
  return /^(\d{6})((?:19|20)\d{6})(\d{3})([0-9a-zA-Z])$/.test(idStr + '')
}

/**
 * 是否有效固话号码 (3-4位区号 + 7-11位号码)
 * @param {string | number} telNumber 验证字符串
 * @return {boolean}
 */
function isTel(telNumber: string | number): boolean {
  return /^(\(?[0-9]{3,4}\)?\s*-\s*)?[0-9]{7,11}$/i.test(telNumber + '')
}

/**
 * 是否有效手机号码
 * @param {string | number} phoneNumber 验证字符串
 * @return {boolean}
 */
function isMobile(phoneNumber: string | number): boolean {
  return /^[1][3-9]\d{9}$/i.test(phoneNumber + '')
}

/**
 * 是否有效电子邮箱
 * @param {string} emailStr 验证字符串
 * @return {boolean}
 */
function isEmail(emailStr: string): boolean {
  return /^[a-z]?([a-z0-9]*[-_]?[a-z0-9.]+)*@([a-z0-9]*[-_]?[a-z0-9]+)+[.][a-z]{2,3}([.][a-z]{2})?$/i.test(
    emailStr + ''
  )
}

/**
 * 是否有效ip地址，包括v4/v6
 * @param {string} ipStr 验证字符串
 * @return {boolean}
 */
function isIp(ipStr: string): boolean {
  return isIpv4(ipStr) || isIpv6(ipStr)
}

/**
 * 是否有效ipv4地址
 * @param {string} ipStr 验证字符串
 * @return {boolean}
 */
function isIpv4(ipStr: string): boolean {
  return /^((25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d))).){3}(25[0-5]|2[0-4]\d|((1\d{2})|([1-9]?\d)))$/.test(
    ipStr
  )
}

/**
 * 是否有效ipv6地址
 * @param {string} ipStr 验证字符串
 * @return {boolean}
 */
function isIpv6(ipStr: string): boolean {
  let str = ipStr.replace('::', ':')
  const match =
    /^(?<segments>([a-f0-9]{1,4}(:|$))+)(\/\d{0,3})?(%\d{1,5})?$/.exec(str)
  return (
    match != null &&
    ipStr.split('::').length < 3 &&
    (match as any).groups.segments.split(':').length < 9
  )
}

/**
 * 是否包含中文字符
 * 基于https://www.unicode.org/Public/5.0.0/ucd/Unihan.html
 * @param {string} str 验证字符串
 * @return {boolean}
 */
function hasChinese(str: string): boolean {
  return /[\u3400-\u4db5\u4e00-\u9fbb\uff00-\uffef\u2e80-\u2eff\u3000-\u303f\u31c0-\u31ef]/.test(
    str + ''
  )
}

/**
 * 是否全部为小写字符
 * @param {string} str 验证字符串
 * @return {boolean}
 */
function isLowerCase(str: string): boolean {
  return /^[a-z]+$/.test(str + '')
}

/**
 * 是否全部为大写字符
 * @param {string} str 验证字符串
 * @return {boolean}
 */
function isUpperCase(str: string): boolean {
  return /^[A-Z]+$/.test(str + '')
}

/**
 * 将科学计数法数字转换为10进制数字字符串
 * @param {number | string} number 科学计数数字
 * @return {string} 如果不是有效科学计数数字直接返回原值字符串
 */
function toNumberString(number: number | string): string {
  let rs = parseFloat(number + '') + ''
  const match =
    /^(?<dir>[+-])?(?<decimal>[1-9][0-9]*(\.[0-9]+)?)e(?<exponential>[+-]?[0-9]+)$/.exec(
      rs
    )
  if (match) {
    const dir = (match as any).groups.dir
    const decimal = (match as any).groups.decimal
    const exponential = (match as any).groups.exponential
    const pair = decimal.split('.')
    if (exponential[0] === '-') {
      let zeroSize = parseInt(exponential) - pair[0].length
      console.log(zeroSize, 'xxxx')
      rs = decimal.replace('.', '')
      while (zeroSize++) {
        rs = '0' + rs
      }
      rs = '0.' + rs
    } else {
      let zeroSize = parseInt(exponential) - pair[1].length
      console.log(zeroSize, 'yyy')
      rs = decimal.replace('.', '')
      while (zeroSize--) {
        rs += '0'
      }
    }
    if (dir === '-') {
      rs = '-' + rs
    }
  }
  return rs
}

/**
 * 是否为数字格式字符串，包括整数/小数/负数
 * @param {string} str 验证字符串
 * @param {number} [precision] 最大精度，表示整个数字字符串的长度。如999.99的精度就是5。取值范围1-21。如果为空表示无限制
 * @param {number} [scale=0] 最大小数精度，表示小数部分数字位数。取值范围0-16
 * @return {boolean}
 */
function isDecimal(
  str: string | number,
  precision: number,
  scale: number = 0
): boolean {
  const numStr = toNumberString(str)
  if (precision > 0) {
    if (numStr.replace(/^[+-]|\./g, '').length > precision) return false
  }

  const decimal = numStr.split('.')[1]
  if (decimal && decimal.length != scale) return false

  return true
}

export {
  isIdNumber,
  isTel,
  isMobile,
  isEmail,
  isIp,
  isIpv4,
  isIpv6,
  hasChinese,
  isLowerCase,
  isUpperCase,
  toNumberString,
  isDecimal,
}
